package qe.spider.vo;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Data
@ToString(doNotUseGetters = true)
@Slf4j
public class Stock {
    @SerializedName(value = "stock_code", alternate = "Code")
    private String stock_code;

    @SerializedName(value = "new", alternate = "_new")
    private Integer _new;

    @SerializedName(value = "stock_name", alternate = "Name")
    private String stock_name;
    @SerializedName(value = "jiage", alternate = "Price")
    private String jiage;
    @SerializedName(value = "zhangfu", alternate = "Rate")
    private String zhangfu;
    private String gang;
    private Integer MIcon;

    @SerializedName(value = "ZJB", alternate = "Buy")
    private BigDecimal ZiJinBuy;

    @SerializedName(value = "ZJS", alternate = "Sell")
    private BigDecimal ZiJinSell;
    @SerializedName(value = "ZJJE", alternate = "ZLJE")
    private BigDecimal ZiJinJingE;

    @SerializedName(value = "plate", alternate = "Tude")
    private String plate;
    private Date grabTime;
    @SerializedName(value = "CJE", alternate = "ChengJiaoE")
    private BigDecimal ChengJiaoE;
    @SerializedName(value = "Ratio", alternate = "ShiJiHuanShouLv")
    private BigDecimal ShiJiHuanShouLv;
    private BigDecimal Speed;
    @SerializedName(value = "SJLTP", alternate = "ShiJiLiuTongZhi")
    private BigDecimal ShiJiLiuTongZhi;

    @SerializedName(value = "QJZF", alternate = "QuJianZhangFu")
    private BigDecimal QuJianZhangFu;

    @Expose
    private transient Set<String> plateSet = new HashSet<>();

    public Boolean belongToPlate(String p) {
        return getPlates().contains(p);
    }

    public Boolean belongToPlate(List<String> ps) {
        return getPlates().stream().anyMatch(ps::contains);
    }

//    public Date getGrabTime() {
//        return this.grabTime == null ? this.grabTime = new Date() : this.grabTime;
//    }

    public Set<String> getPlates() {
        if (null != plate && !plate.isEmpty() && plateSet.isEmpty())
            this.plateSet.addAll(Arrays.stream(this.plate.split("、")).map(String::trim).collect(Collectors.toSet()));
        return this.plateSet;
    }

    public Stock setPlate(String plate) {
        this.plate = plate;
        this.plateSet.addAll(Arrays.stream(this.plate.split("、")).map(String::trim).filter(StrUtil::isNotBlank).collect(Collectors.toSet()));
        return this;
    }

    public String getShortPlates() {
        return getPlates().stream().limit(2).collect(Collectors.joining(","));
    }


    public Double getZhuBuyZhanBi() {
        if (bigBuyRate != null) return bigBuyRate;
        return ZiJinBuy == null || ChengJiaoE == null ? null : ZiJinBuy.doubleValue() / ChengJiaoE.doubleValue();
    }

    public Double getZhuSellZhanBi() {
        if (bigSellRate != null) return bigSellRate;
        return ZiJinSell == null || ChengJiaoE == null ? null : Math.abs(ZiJinSell.doubleValue() / ChengJiaoE.doubleValue());
    }

    private Double ZhuLiJingLiang = null;


    public Double getZhuLiJingLiang() {
        if (ZhuLiJingLiang == null || ZhuLiJingLiang == 0.0)
            return ZhuLiJingLiang = ZiJinJingE == null || ShiJiLiuTongZhi == null ? null : ZiJinJingE.doubleValue() / ShiJiLiuTongZhi.doubleValue();
        else return ZhuLiJingLiang;
    }

    public Stock code(String code) {
        this.stock_code = code;
        return this;
    }

    public Stock name(String name) {
        this.stock_name = name;
        return this;
    }

    public String codeName() {
        return getStock_code() + "（" + getStock_name() + ")";
    }

    private Integer zhangTingCnt5;
    private Integer dieTingCnt5;

    public Stock zhangTingCnt5(Integer zhangTingCnt5) {
        this.zhangTingCnt5 = zhangTingCnt5;
        return this;
    }

    public Stock dieTingCnt5(Integer dieTingCnt5) {
        this.dieTingCnt5 = dieTingCnt5;
        return this;
    }

    public String zhangdieTingInfo() {
        return stock_code + "：涨停" + zhangTingCnt5 + "次，跌停" + dieTingCnt5 + "次";
    }

    public Boolean existZhangDieTing5Day() {
        return (zhangTingCnt5 != null && zhangTingCnt5 > 0) || (dieTingCnt5 != null && dieTingCnt5 > 0);
    }

    public void setZhangfu(String zhangfu) {
        if (StrUtil.isEmpty(zhangfu)) return;
        this.zhangfu = zhangfu.trim().endsWith("%") ? zhangfu.trim().replace("+", "") : (zhangfu.trim().replace("+", "") + "%");
    }

    public Double numZhangFu() {
        if (StrUtil.isEmpty(zhangfu)) return 0.0;
        return zhangfu.trim().endsWith("%") ? new BigDecimal(zhangfu.trim().replace("%", "")).doubleValue() : new BigDecimal(zhangfu.trim()).doubleValue();
    }

    //是否涨停（科创板和创业板：20%，主板是10%）
    public Boolean isUpLimit() {
        if (zhangTingJia != null) { //根据涨停价判断
            return currentPrice().map(current -> zhangTingJia != null && current.compareTo(zhangTingJia) >= 0).orElse(false);
        }
        if (zuoShou != null) {//根据昨收判断
            if (stock_code.startsWith("688") || stock_code.startsWith("30")) {//涨停价为昨收*120%  zuoShou.multiply(new BigDecimal(1.2))
                return currentPrice().map(current -> current.compareTo(zuoShou.multiply(new BigDecimal(1.2))) >= 0).orElse(false);
            } else { //10%
                return currentPrice().map(current -> current.compareTo(zuoShou.multiply(new BigDecimal(1.1))) >= 0).orElse(false);
            }
        }
        Double upLimit = numZhangFu();//根据涨幅判断
        if (stock_code.startsWith("688")) return upLimit >= 19.7 && upLimit <= 20.1;//科创板
        else if (stock_code.startsWith("30")) return upLimit >= 19.7 && upLimit <= 20.1; //创业板
        else return upLimit >= 9.7 && upLimit <= 10.2;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Stock stock = (Stock) o;
        if (null != stock_code && !stock_code.isEmpty()) return stock_code.equals(stock.stock_code);
        else if (null != stock_name && !stock_name.isEmpty()) return stock_name.equals(stock.stock_name);
        else return super.equals(o);
    }

    @Override
    public int hashCode() {
        if (null != stock_code && !stock_code.isEmpty()) return Objects.hash(stock_code);
        else if (null != stock_name && !stock_name.isEmpty()) return Objects.hash(stock_name);
        else return super.hashCode();
    }

    public String getMarket() {
        if (!StrUtil.isEmpty(market)) return market;
        if (StrUtil.startWith(getStock_code(), "60")) market = "SH";
        if (StrUtil.startWith(getStock_code(), "00") || StrUtil.startWith(getStock_code(), "30")) market = "SZ";
        return market;
    }

    @Expose
    private String market;
    //    private BigDecimal liuTongShiZhi;
    @Expose
    private BigDecimal zhangSu4min;
    @Expose
    private BigDecimal xianShou;
    @Expose
    private Boolean xianShouZhang;
    //    private BigDecimal zongJinE;
    @Expose
    private BigDecimal huanShou;
    @Expose
    private BigDecimal liangBi;
    @Expose
    private Boolean liKong;
    @Expose
    private Boolean liHao;
    @Expose
    private BigDecimal zuoShou;
    @Expose
    private BigDecimal kaiPan;
    @Expose
    private BigDecimal renQi;
    @Expose
    private Integer renqiRanking;
    @Expose
    private String suoShuHangYe;
    @Expose
    private String suoShuGaiNian;
    @Expose
    private BigDecimal zuiGaoJia;
    @Expose
    private BigDecimal zhangTingJia;
    @Expose
    private BigDecimal dieTingJia;
    @Expose
    private BigDecimal bigBuy;  //大单买入金额
    @Expose
    private BigDecimal veryBigBuy;//特大单买入金额
    @Expose
    private BigDecimal bigSell;//大单卖出金额
    @Expose
    private BigDecimal veryBigSell;//特大单卖出金额
    @Expose
    private Double bigBuyRate;  //主买占比 = (大单买入金额+特大单买入金额)/总金额
    @Expose
    private Double bigSellRate;  //主卖占比 = (大单卖出金额+特大单卖出金额)/总金额
    @Expose
    private BigDecimal shoupanPrice;//收盘价
    @Expose
    private BigDecimal highPrice;//最高价
    @Expose
    private BigDecimal lowPrice;//最低价
    @Expose
    private BigDecimal avgPrice;//均价
    @Expose
    private BigDecimal kaipanRate;//开盘涨幅

    public void setSuoShuHangYe(String suoShuHangYe) {
        this.suoShuHangYe = suoShuHangYe;
        this.plateSet.addAll(Arrays.stream(this.suoShuHangYe.split("、")).map(String::trim).collect(Collectors.toSet()));
    }

    public void setSuoShuGaiNian(String suoShuGaiNian) {
        this.suoShuGaiNian = suoShuGaiNian;
        this.plateSet.addAll(Arrays.stream(this.suoShuGaiNian.replaceAll("【", "").replaceAll("】", "").split(";")).map(String::trim).collect(Collectors.toSet()));
    }

    //当前价格
    public Optional<BigDecimal> currentPrice() {
        if (NumberUtil.isNumber(jiage)) return Optional.of(new BigDecimal(jiage));
        else return Optional.empty();
    }

    private Date zhabanTime;

    //涨停版被打开（当前未涨停，但之前最高价==涨停价）。重启系统则自动重置为未炸板
    public Boolean isZhaBan() {
        if (zhabanTime != null) return true;  //炸板过，就存炸板的时间
        Boolean zha = currentPrice().isPresent() && null != zuiGaoJia && null != zhangTingJia &&
                zuiGaoJia.compareTo(zhangTingJia) == 0 &&   //最高价==涨停价
                currentPrice().get().compareTo(zhangTingJia) < 0; //当前价格小于涨停价
        if (zha) {
            zhabanTime = grabTime;
            return true;
        } else return false;
    }

    public Boolean isNsNew(Stock ns) {
//        return DateUtil.format(ns.grabTime, "HH:mm").compareTo(DateUtil.format(this.grabTime, "HH:mm")) < 0;
        return ns.grabTime == null && this.grabTime != null && ns.grabTime.after(this.grabTime);
    }

    public Stock merge(Stock s) {
        if (null == s || !this.stock_code.equals(s.getStock_code())) return this;
//        if (s.grabTime.before(this.grabTime))
//            log.info("新抓取时间{}早于本时间{}", DateUtil.format(s.getGrabTime(), "HH:mm:ss"), DateUtil.format(this.getGrabTime(), "HH:mm:ss"));
        if (s.grabTime == null || s.grabTime.before(this.grabTime)) {
            log.warn("新票抓取时间早于当前，不更新");
            return this;// 新票抓取时间早于当前，不更新
        }
        /*if (s.grabTime != null && this.grabTime != null && s.grabTime.after(this.grabTime)) */
        this.grabTime = s.grabTime;
        if (null != s.jiage) this.jiage = s.jiage;
        if (null != s.zhangfu) this.setZhangfu(s.zhangfu);
        if (null != s.ZiJinBuy) this.ZiJinBuy = s.ZiJinBuy;
        if (null != s.ZiJinSell) this.ZiJinSell = s.ZiJinSell;
        if (null != s.getZhuLiJingLiang()) this.setZhuLiJingLiang(s.getZhuLiJingLiang());
        if (null != s.ZiJinJingE) this.ZiJinJingE = s.ZiJinJingE;
        if (null != s.ChengJiaoE) this.ChengJiaoE = s.ChengJiaoE;
        if (null != s.ShiJiHuanShouLv) this.ShiJiHuanShouLv = s.ShiJiHuanShouLv;
        if (null != s.Speed) this.Speed = s.Speed;
        if (null != s.zhangSu4min) this.zhangSu4min = s.zhangSu4min;
        if (null != s.ShiJiLiuTongZhi) this.ShiJiLiuTongZhi = s.ShiJiLiuTongZhi;
        if (null != s.zhangTingCnt5 && s.zhangTingCnt5 != zhangTingCnt5) this.zhangTingCnt5 = s.zhangTingCnt5;
        if (null != s.dieTingCnt5 && s.dieTingCnt5 != dieTingCnt5) this.dieTingCnt5 = s.dieTingCnt5;

        if (null != s.QuJianZhangFu) this.QuJianZhangFu = s.QuJianZhangFu;
        if (null != s.market) this.market = s.market;
        if (null != s.xianShou) this.xianShou = s.xianShou;
        if (null != s.xianShouZhang) this.xianShouZhang = s.xianShouZhang;
        if (null != s.huanShou) this.huanShou = s.huanShou;
        if (null != s.liangBi) this.liangBi = s.liangBi;
        if (null != s.liKong) this.liKong = s.liKong;
        if (null != s.liHao) this.liHao = s.liHao;
        if (null != s.zuoShou) this.zuoShou = s.zuoShou;
        if (null != s.kaiPan) this.kaiPan = s.kaiPan;
        if (null != s.renQi) this.renQi = s.renQi;
        if (null != s.renqiRanking) this.renqiRanking = s.renqiRanking;
        if (null != s.zuiGaoJia) this.zuiGaoJia = s.zuiGaoJia;
        if (null != s.zhangTingJia) this.zhangTingJia = s.zhangTingJia;
        if (null != s.dieTingJia) this.dieTingJia = s.dieTingJia;
        if (null != s.suoShuHangYe) this.setSuoShuHangYe(s.suoShuHangYe);
        if (null != s.suoShuGaiNian) this.setSuoShuGaiNian(s.suoShuGaiNian);
        if (null != s.getPlates()) this.plateSet.addAll(s.getPlates());

        if (null != s.bigBuy) this.bigBuy = s.bigBuy;
        if (null != s.veryBigBuy) this.veryBigBuy = s.veryBigBuy;
        if (null != s.bigSell) this.bigSell = s.bigSell;
        if (null != s.veryBigSell) this.veryBigSell = s.veryBigSell;
        if (null != s.bigBuyRate) this.bigBuyRate = s.bigBuyRate;
        if (null != s.bigSellRate) this.bigSellRate = s.bigSellRate;

        if (null != s.shoupanPrice) this.shoupanPrice = s.shoupanPrice;
        if (null != s.highPrice) this.highPrice = s.highPrice;
        if (null != s.lowPrice) this.lowPrice = s.lowPrice;
        if (null != s.avgPrice) this.avgPrice = s.avgPrice;
        if (null != s.kaipanRate) this.kaipanRate = s.kaipanRate;

        if (null != s.zhabanTime) this.zhabanTime = s.zhabanTime;

        return this;
    }
}
